#include "os_common.h"

VOID
_append_data( PUCHAR pData, USHORT size, tkip_t *p )
{
	ULONG   ulValue;

	//931130.6.a
	if( p->bytes_in_M )
    {
		while( p->bytes_in_M!=4 && size ) 
		{
			// Append the byte to our word-sized buffer
			p->Mb[p->bytes_in_M] = *pData; // Only be used in Little endian only

			pData++;
			size--;
			p->bytes_in_M++;
		}
	}

	// Consuming the data
	while( size>=4 || p->bytes_in_M==4 )
	{
		if( p->bytes_in_M == 4 )
    	{
			// 931130.6.b
	        	p->L ^= cpu_to_le32( p->M ); //20061011 anson's endian
			p->bytes_in_M = 0;
		}
		else
		{
			OS_MEMORY_COPY( &ulValue, pData, sizeof(ULONG) );
			// 931130.6.c
			p->L ^= cpu_to_le32( ulValue ); //20061011 anson's endian
			pData += 4;
			size -= 4;
		}

        p->R ^= ROL32(p->L, 17);
        p->L += p->R;
        p->R ^= ((p->L & 0xff00ff00) >> 8) | ((p->L & 0x00ff00ff) << 8);
        p->L += p->R;
        p->R ^= ROL32(p->L, 3);
        p->L += p->R;
        p->R ^= ROR32(p->L, 2);
        p->L += p->R;
	}

	// 931130.6.d
	while( size )
	{
		p->Mb[p->bytes_in_M] = *pData; // Only be used in Little endian only

		pData++;
		size--;
		p->bytes_in_M++;
    }
}

VOID
Mds_MicGet( IN PVOID p1, IN PVOID p2, IN PUCHAR pKey, OUT PUCHAR pMic )
{
	PRXLAYER1 pRxLayer1 = p2;
	struct	Data_Frame* pDFrame;
	PUCHAR	pda, psa;
	PUCHAR	IndicateBufferAddress;
	tkip_t  tkip;
	ULONG	end_pad = 0;
	ULONG	Priority = 0;
	UCHAR	min_pad[5] = { 0x5a, 0x0, 0x0, 0x0, 0x0 };
	USHORT	IndicateBufferSize, BufferTotalSize;
	UCHAR	i, BufNum;


	// Set the key to a new value
	// function: tkip_set_key( pkey )
	tkip.K0 = cpu_to_le32( *((PULONG)pKey) ); //20061011 anson's endian// @@
	tkip.K1 = cpu_to_le32( *((PULONG)pKey + 1) ); //20061011 anson's endian // @@

	// Clear the internal message,
	// resets the object to the state just after construction.
	// function: clear()
    tkip.L = tkip.K0;
    tkip.R = tkip.K1;
    tkip.M = 0;
    tkip.bytes_in_M = 0;

	// Set DA SA
	pDFrame = (struct Data_Frame*)pRxLayer1->BufferQueue[0].pBufferAddress;
	pda = pDFrame->Addr1;
	psa = pDFrame->Addr3;
	if( !pDFrame->frame_control.from_ds )
    {
		pda = pDFrame->Addr1;
		psa = pDFrame->Addr2;
    }

	// Append DA
	_append_data( pda, 6, &tkip );

	// Append SA
	_append_data( psa, 6, &tkip );

	// Append priority[0] + 3 octet reserved (0) field [0][0][0]
	_append_data( (PUCHAR)&Priority, 4, &tkip );

	// Append data
	BufNum = pRxLayer1->BufferNumber;
	BufferTotalSize = pRxLayer1->BufferTotalSize - 8 - 24; // Exclude 8 byte mic + 24 header
	i = 0;
	while( BufferTotalSize )
	{
		IndicateBufferSize = pRxLayer1->BufferQueue[i].BufferSize;
		IndicateBufferAddress = pRxLayer1->BufferQueue[i].pBufferAddress;
		if (i == 0)
		{
			IndicateBufferSize -= 24;//exclude header
			IndicateBufferAddress += 24;
		}

		IndicateBufferSize = (IndicateBufferSize > BufferTotalSize) ? BufferTotalSize : IndicateBufferSize;
		_append_data( IndicateBufferAddress, IndicateBufferSize, &tkip );

		BufferTotalSize -= IndicateBufferSize;
		i++;
	}

/*
	for(i=0; i<BufNum; i++)
	{
        IndicateBufferSize = pRxLayer1->BufferQueue[i].BufferSize;
        IndicateBufferAddress = pRxLayer1->BufferQueue[i].pBufferAddress;

		if (i == 0)
		{
			IndicateBufferSize -= 24;//exclude header
			IndicateBufferAddress += 24;
		}

		if (i == (BufNum-1))
			IndicateBufferSize -= 8;//exclude MIC

		_append_data( IndicateBufferAddress, IndicateBufferSize, &tkip );
	}
*/

	// Append the minimum padding
	_append_data( min_pad, 5, &tkip );

	// Append zeroes until the length is a multiple of 4 */
	if( tkip.bytes_in_M )
		_append_data( (PUCHAR)&end_pad, 4 - tkip.bytes_in_M, &tkip );

	// result
	//---20061011 add by anson's endian
	tkip.L = cpu_to_le32( tkip.L );
	tkip.R = cpu_to_le32( tkip.R ); 
	//---end 20061011 add 
	OS_MEMORY_COPY( pMic, &tkip.L, sizeof(ULONG) );
	OS_MEMORY_COPY( pMic + 4, &tkip.R, sizeof(ULONG) );
}


VOID
Mds_MicFill( IN PVOID p1, IN PVOID p2, IN PUCHAR XmitBufAddress )
{
	PADAPTER Adapter = p1;
	PDESCRIPTOR pDes = p2;
	PMDS pMds = &Adapter->Mds;
	//PT00_DESCRIPTOR	pT00;   //20061011 marked by anson's endian
	PUCHAR	pda, psa, BufferAddress;
    tkip_t  tkip;
	ULONG	end_pad = 0;
	ULONG	Priority = 0;
	USHORT	BodyLeft, BufferSize, MicSize;
	UCHAR	min_pad[5] = { 0x5a, 0x0, 0x0, 0x0, 0x0 };
	UCHAR	i;
	PUCHAR	mic_key = NULL;
	T00_DESCRIPTOR	T00; //20061011 add by anson's endian

	//[20040712 WS] : key is not valid if using WPA_NONE
	//In IBSS, it is possible to transmit multicast frames
	if ((*(XmitBufAddress+12)&1) == 0) // unicast frames
	{
		if (CURRENT_PAIRWISE_KEY_OK)
			mic_key = CURRENT_PAIRWISE_KEY;
	}
	if (mic_key == NULL)
	{
		if (CURRENT_GROUP_KEY_OK)
			mic_key = CURRENT_GROUP_KEY;
	}

	// Set the key to a new value
	// function: tkip_set_key( pkey )
	if (mic_key != NULL)
	{
		tkip.K0 = cpu_to_le32( *((PULONG)mic_key) ); //20061011 anson's endian // @@
		tkip.K1 = cpu_to_le32( *((PULONG)mic_key + 1) ); //20061011 anson's endian // @@
	}
	else
	{
		tkip.K0 = 0;
		tkip.K1 = 0;
	}
	// Clear the internal message,
	// resets the object to the state just after construction.
	// function: clear()
    tkip.L = tkip.K0;
    tkip.R = tkip.K1;
    tkip.M = 0;
    tkip.bytes_in_M = 0;

	// Set DA SA
	if( CURRENT_BSS_TYPE == ESS_NET )
		pda = XmitBufAddress + 24;
	else
		pda = XmitBufAddress + 12;	//USB header(8) ,frame control(2), and duration(2)
	psa = XmitBufAddress + 18;

	// Append DA
	_append_data( pda, 6, &tkip );

	// Append SA
	_append_data( psa, 6, &tkip );

	// Append priority[0] + 3 octet reserved (0) field [0][0][0]
	_append_data( (PUCHAR)&Priority, 4, &tkip );

	// Append data
	BufferAddress = XmitBufAddress;
	BodyLeft = pDes->buffer_total_size - 8; //exclude MIC
	while (BodyLeft)
	{
		//---20061011 anson's endian
		//pT00 = (PT00_DESCRIPTOR)BufferAddress; // @@
		//BufferSize = (USHORT)pT00->T00_frame_length - 24; // 24 for 802.11 header 
		T00.value = cpu_to_le32( *(PULONG)BufferAddress );
		BufferSize = (USHORT)T00.T00_frame_length - 24; // 24 for 802.11 header
		//---end 20061014 anson's endian 
		MicSize = BodyLeft;
		if( BufferSize < BodyLeft ) //931130.6.e
			MicSize = BufferSize;
		_append_data( BufferAddress + 32, MicSize, &tkip ); // 8 for USB hdr, 24 for 802.11 hdr

		BodyLeft -= MicSize;
		BufferSize += 24 + 8 + 3; // 24 for 802.11hdr, 8 byte for current USB header, 3 for 4n alignment
		BufferSize &= ~0x3; //4n alignment
		BufferAddress += BufferSize; //931130.6.f
	}

	// Append the minimum padding
	_append_data( min_pad, 5, &tkip );

	// Append zeroes until the length is a multiple of 4 */
	if( tkip.bytes_in_M )
		_append_data( (PUCHAR)&end_pad, 4 - tkip.bytes_in_M, &tkip );


	// 931130.6.g
	MicSize = 0;
	i = 0;
	//---20061011 add by anson's endian
	tkip.L = cpu_to_le32( tkip.L );
	tkip.R = cpu_to_le32( tkip.R );
	//---end 20061011 add
	while( MicSize < 8 )
    {
		OS_MEMORY_COPY( pMds->MicWriteAddress[ i ], tkip.LR, pMds->MicWriteSize[ i ] );
		MicSize += pMds->MicWriteSize[ i ];
		i++;
    }
}


